﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Campus {
    public class MoveAbility : Ability {
        public Vector2 FinalDestination {get; set;}
        private Queue<Vector2> m_destinationQueue;
        private bool m_hasCopiedQueue = false;

        public delegate bool PrematureStop();

        public PrematureStop StopDelegate { private get; set; }
        
        public MoveAbility(Unit owner, Vector2 destination)
            : base(MenuIcons.MoveIcon, owner, null, TargetTypes.PointTarget) {
            FinalDestination = destination;
            m_hasCopiedQueue = false;
            StopDelegate = delegate() { return false; };

            MenuDelegate = delegate(string option) {
                Campus.cursor.ActionState = CursorActionState.move;
                Campus.cursor.ClickMethod = delegate(Vector2 gamePoint) {
                    FinalDestination = gamePoint;
                    Owner.SetCurrentAbility(this);
                    Campus.cursor.ClickMethod = null;
                    Campus.cursor.ActionState = CursorActionState.idle;
                };
            };
        }

        public MoveAbility(MoveAbility copySource)
            : base(copySource) {
            FinalDestination = copySource.FinalDestination;
            StopDelegate = copySource.StopDelegate;
            m_destinationQueue = new Queue<Vector2>();
            m_hasCopiedQueue = copySource.m_hasCopiedQueue;

            MenuDelegate = delegate(string option) {
                Campus.cursor.ActionState = CursorActionState.move;
                Campus.cursor.ClickMethod = delegate(Vector2 gamePoint) {
                    FinalDestination = gamePoint;
                    Owner.SetCurrentAbility(this);
                    Campus.cursor.ClickMethod = null;
                    Campus.cursor.ActionState = CursorActionState.idle;
                };
            };
        }

        private void SetUpQueue() {
            Unit unit = (Unit)Owner;
            Vector2 tilePosition;
            Point startTile, endTile;

            Vector2 unitPosition = new Vector2(unit.Position.X + unit.Size.X / 2.0f , 
                                               unit.Position.Y + unit.Size.Y);

            // Get the tile the unit is currently on
            Owner.PlayerOwner.CurrentLevel.GetGridPositionForPoint(unitPosition, out tilePosition);
            startTile = new Point((int)tilePosition.X, (int)tilePosition.Y);

            // Get the tile for the destination
            Owner.PlayerOwner.CurrentLevel.GetGridPositionForPoint(FinalDestination, out tilePosition);
            endTile = new Point((int)tilePosition.X, (int)tilePosition.Y);

            if (startTile == endTile) {
                Vector2 dest = FinalDestination;
                Vector2 normalizer = new Vector2(unit.Size.X / 2.0f, unit.Size.Y);
                dest -= normalizer;
                m_destinationQueue.Enqueue(dest);
            } else {
                 List<Point> tileList = unit.PlayerOwner.CurrentLevel.GetPath(startTile, endTile);

                if (tileList != null) {
                    Vector2 dest;
                    Vector2 normalizer = new Vector2(unit.Size.X / 2.0f, unit.Size.Y);

                    Queue<Vector2> destinationQueue = new Queue<Vector2>();

                    // Add all the tiles in the path except the last one
                    for (int j = 1; j < tileList.Count - 1; j++) {
                        Point tile = tileList[j];
                        Owner.PlayerOwner.CurrentLevel.GetPointForGridPosition(tile, out dest);
                        dest -= normalizer;
                        destinationQueue.Enqueue(dest);
                    }

                    // Add the final destination manually to conserve where within the final tile the unit should go
                    dest = FinalDestination;
                    dest -= normalizer;
                    destinationQueue.Enqueue(dest);

                    m_destinationQueue = destinationQueue;
                }
            }
        }

        public override Ability Clone() {
            return new MoveAbility(this);
        }

        public override void Update(GameTime gameTime, bool checkInput, bool updateBoundingBox) {
            Unit unit = (Unit)Owner;
            if (!m_hasCopiedQueue) {
                //generate the queue
                SetUpQueue();
                m_hasCopiedQueue = true;
                unit.DestinationQueue = m_destinationQueue;
            }
            if (StopDelegate()) {
                unit.StopMoving();
                IsAbilityDone = true;
            }
            if (unit.DestinationQueue.Count == 0) {
                IsAbilityDone = true;
            }
        }
    }
}
